package com.jvm.jdbc.demo3;

import com.jvm.jdbc.util.ConnectUtil;
import com.jvm.jdbc.util.User;

import java.sql.Connection;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;
import java.util.ArrayList;
import java.util.List;

/**
 * <p>
 * Jdbctemplate 使用接口
 * 使用接口回调类和使用实现类的方式比较：
 *          为什么spring不用传统的模板方法，而加之以Callback进行配合呢？
 *          试想，如果父类中有10个抽象方法，而继承它的所有子类则要将这10个抽象方法全部实现，子类显得非常臃肿。
 *          而有时候某个子类只需要定制父类中的某一个方法该怎么办呢？这个时候就要用到Callback回调了。
 * </p>
 *
 * @author qingshan
 * @since 2020-10-11 15:27
 */
public class JdbcTemplate {

    /**
     * 对外查询方法 query
     * @param stmt
     * @return
     * @throws SQLException
     */
    private Object query(StatementCallback stmt) throws SQLException{
        return execute(stmt);
    }

    /**
     *
     * @param action
     * @return
     * @throws SQLException
     */
    public final Object execute(StatementCallback action) throws SQLException {
        Connection con = ConnectUtil.getConnection();
        Statement stmt = null;
        try {
            stmt = con.createStatement();
            Object result = action.doInStatement(stmt);//abstract method
            return result;
        } catch (SQLException ex) {
            ex.printStackTrace();
            throw ex;
        } finally {
            try {
                stmt.close();
            } catch (SQLException e) {
                e.printStackTrace();
            }
            try {
                if(!con.isClosed()) {
                    try {
                        con.close();
                    } catch (SQLException e) {
                        e.printStackTrace();
                    }
                }
            } catch (SQLException e) {
                e.printStackTrace();
            }

        }
    }

    /**
     * 内部类方式
     * @param sql
     * @return
     * @throws SQLException
     */
    public Object query1(final String sql) throws SQLException {
        class QueryStatementCallback implements StatementCallback {
            @Override
            public Object doInStatement(Statement stmt) throws SQLException {
                ResultSet rs = stmt.executeQuery(sql);
                List<User> userList = new ArrayList<>();
                User user = null;
                while (rs.next()) {
                    user = new User();
                    user.setId(rs.getInt("id"));
                    user.setUserName(rs.getString("user_name"));
                    user.setAge(rs.getInt("age"));
                    user.setSex(rs.getString("sex"));
                    userList.add(user);
                }
                return userList;
            }
        }

        JdbcTemplate jt = new JdbcTemplate();
        return jt.query(new QueryStatementCallback());
    }

    /**
     * 匿名类方式
     * @param sql
     * @return
     * @throws Exception
     */
    public Object query2(final String sql) throws Exception{
        JdbcTemplate jt = new JdbcTemplate();
        return jt.query(stmt -> {
            ResultSet rs = stmt.executeQuery(sql);
            List<User> userList = new ArrayList<>();
            User user = null;
            while (rs.next()) {
                user = new User();
                user.setId(rs.getInt("id"));
                user.setUserName(rs.getString("user_name"));
                user.setAge(rs.getInt("age"));
                user.setSex(rs.getString("sex"));
                userList.add(user);
            }
            return userList;
        });
    }

    public static void main(String[] args) throws Exception {

        String sql = "select * from User";
        JdbcTemplate t = new JdbcTemplate();

        List<User> userList = (List<User>) t.query1(sql);
        List<User> userList2 = (List<User>) t.query2(sql);
        System.out.println(userList);
        System.out.println(userList2);
    }
}
